`timescale 1ns/1ps

`include "code\source\P4\frame_sync.v"
module test_frame_sync;

    initial begin
        $dumpfile("./release/test_frame_sync.vcd");
        $dumpvars(0, test_frame_sync);
    end

  // Generate clock
  reg clk;
  initial clk = 0;
  always #1 clk = ~clk;
  
  // Input registers
  reg reset, din, din_valid;
  
  // Output wires
  wire dout_valid;
  wire [7:0] control;
  wire [7:0] length;
  wire [7:0] dout;
  wire sync;
  wire recv_done;
  wire crc_check;

  // Tasks
  integer seed = 12314;
  integer i;
  integer sync_word = 32'h0dd4259f;
  task shift_out(input [31:0] _n, input [5:0] len);
    begin
      $display("shift out (MSB First): %x length: %d", _n, len);
      for (i = 0; i < len; i = i + 1) begin
        din = 1 & (_n >> (len - i - 1));
        @(negedge clk);
      end
    end
  endtask

  initial begin
    reset = 1;
    din = 0;
    din_valid = 0;
    @(negedge clk)
    reset = 0;

    repeat(2) @(posedge  clk);

    // naive test
    @(negedge clk)
    din_valid = 1;
    shift_out($random(seed), 32);
    shift_out(32'h55555555, 32);
    shift_out(32'h5555, 16);
    shift_out(sync_word, 32);
    shift_out(8'haa, 8);
    shift_out(3, 8);
    shift_out(24'h112233, 24);
    shift_out(16'he5f1, 16);
    shift_out($random(seed), 32);
    din_valid = 0;
    
    repeat(2) @(posedge  clk);
    
    // test zero length
    @(negedge clk)
    din_valid = 1;
    shift_out(32'h55555555, 32);
    shift_out(32'h5555, 16);
    shift_out(sync_word, 32);
    shift_out(8'haa, 8);
    shift_out(0, 8);
    shift_out(16'hf2b5, 16);
    din_valid = 0;

    repeat(2) @(posedge  clk);

    // test crc fail
    @(negedge clk)
    din_valid = 1;
    shift_out(32'h55555555, 32);
    shift_out(32'h5555, 16);
    shift_out(sync_word, 32);
    shift_out(8'haa, 8);
    shift_out(0, 8);
    shift_out(16'h0000, 16);
    din_valid = 0;

    repeat(2) @(posedge  clk);

    // test max length
    @(negedge clk)
    din_valid = 1;
    shift_out(32'h55555555, 32);
    shift_out(32'h5555, 16);
    shift_out(sync_word, 32);
    shift_out(8'haa, 8);
    shift_out(255, 8);
    repeat(255) shift_out(8'h88, 8);
    shift_out(16'hd3ae, 16);
    din_valid = 0;
    
    repeat(10) @(posedge clk);

    // Exit the simulation
    $finish;
  end

  always@(negedge clk) begin
    if (dout_valid) begin
      $display(dout);
    end
    else begin if (recv_done) begin
      $display(length);
      $display(control);
      $display({7'b0, crc_check});
      end
    end
  end

  // Device under test (our adder)
  frame_sync dut (.rst_n(~reset), .clk(clk), .dout(dout), .dout_valid(dout_valid), .din(din), .din_valid(din_valid), .sync(sync), .recv_done(recv_done), .control(control), .length(length), .crc_check(crc_check));

endmodule
